package com.ruibang.glass.quality.util;

import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.*;

public class HttpUtils {
    /**
     * Http timeouts
     */
    public static final int DEFAULT_HTTP_CONNECTION_TIMEOUT = 100 * 1000;
    public static final int DEFAULT_HTTP_READ_TIMEOUT = 100 * 1000;
    /**
     * Http connections
     */
    public static final int DEFAULT_MAX_PER_ROUTE = 20;
    public static final int MAX_TOTAL = 200;
    public static final String CHARSET_UTF8 ="UTF-8";
    private static final CloseableHttpClient httpClient = getHttpClient();
    public enum ContentType{

        WILDCARD("*/*"),
        APPLICATION_XML("application/xml"),
        APPLICATION_ATOM_XML("application/atom+xml"),
        APPLICATION_XHTML_XML("application/xhtml+xml"),
        APPLICATION_SVG_XML("application/svg+xml"),
        APPLICATION_JSON("application/json"),
        APPLICATION_FORM_URLENCODED("application/x-www-form-urlencoded"),
        MULTIPART_FORM_DATA("multipart/form-data"),
        APPLICATION_OCTET_STREAM("application/octet-stream");

        private String name;
        private ContentType(String name){
            this.name = name;
        }
        public String value(){
            return this.name;
        }
    }
    /**
     * 绕过验证 (公共方法)
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    public static SSLContext createIgnoreVerifySSL()  {
        SSLContext sc = null;
        try {
            sc = SSLContext.getInstance("SSLv3");
            // 实现一个X509TrustManager接口，用于绕过验证，不用修改里面的方法
            X509TrustManager trustManager = new X509TrustManager() {
                public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,String paramString) throws CertificateException {
                }

                public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,String paramString) throws CertificateException {
                }

                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            sc.init(null, new TrustManager[]{trustManager}, null);
        }catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return sc;
    }

    /**
     * 适合多线程的HttpClient (公共方法)
     * @return CloseableHttpClient
     */
    public static CloseableHttpClient getHttpClient() {
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(createIgnoreVerifySSL()))
                .build();
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        // 设置连接池大小
        connManager.setMaxTotal(MAX_TOTAL);
        connManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
        RequestConfig requestConfig =  RequestConfig.custom()
                .setConnectTimeout(DEFAULT_HTTP_CONNECTION_TIMEOUT)
                .setSocketTimeout(DEFAULT_HTTP_READ_TIMEOUT)
                .build();
        return HttpClients.custom().setConnectionManager(connManager).setDefaultRequestConfig(requestConfig).build();
    }

    /**
     * 执行 一个 带有基础认证的 请求 (公共方法)
     * @param request
     * @param userName
     * @param userPass
     * @return
     */
    public static HttpResponse getBasicAuthortion(HttpUriRequest request, String userName, String userPass){
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(userName, userPass);

        Header header = null;

        try {

            header = new BasicScheme().authenticate(credentials, request);

        } catch (AuthenticationException e) {

            e.printStackTrace();

        }

        request.addHeader(header);

        HttpResponse  response = null;

        try {

            response = httpClient.execute(request);

        } catch (IOException e) {

            e.printStackTrace();

        }
        return response;

    }

    /**
     * POST 方法请求
     * @param url
     * @param text
     * @param contentType
     * @param header
     * @return
     */
    public static String doPost(String url, String text, ContentType contentType, Header... header){
        String result = null;
        CloseableHttpResponse response = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            StringEntity myEntity = new StringEntity(text, CHARSET_UTF8);
            if(header != null){
                for (int i = 0; i <header.length; i++) {
                	httpPost.addHeader(header[i]);
                }
            }
            if(contentType != null){
                httpPost.addHeader("Content-Type",contentType.value());
            }
            httpPost.setEntity(myEntity);
            response = httpClient.execute(httpPost);
            return EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(response != null){
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null ;
    }

//    public ResultBody<String> responseToResultBody(HttpResponse httpResponse){
//        int statusCode = httpResponse.getStatusLine().getStatusCode();
//
//    }

    public static String doGet(String url, Header... headers  ) throws IOException {
        CloseableHttpResponse response = null;
        HttpGet httpGet = new HttpGet(url);
        String result = "";
        if(headers != null){
            for (int i = 0; i <headers.length; i++) {
                httpGet.addHeader(headers[i]);
            }
        }
        response = httpClient.execute(httpGet);
        HttpEntity entity = response.getEntity();
        if (entity != null) {
           result = IOUtils.toString(entity.getContent(), CHARSET_UTF8);
        }
        return result;
    }

    /**
     * post from表单
     * @param url
     * @param param
     * @return
     */
    public static String doPost(String url, Map<String, String> param) {
		// 创建Httpclient对象
		CloseableHttpResponse response = null;
		String resultString = "";
		try {
			// 创建Http Post请求
			HttpPost httpPost = new HttpPost(url);
			httpPost.setHeader("Content-Type", ContentType.APPLICATION_FORM_URLENCODED.name);
			// 创建参数列表
			if (param != null) {
				List<NameValuePair> paramList = new ArrayList<>();
				for (String key : param.keySet()) {
					paramList.add(new BasicNameValuePair(key, param.get(key)));
				}
				// 模拟表单
				UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"utf-8");
				httpPost.setEntity(entity);
			}
			// 执行http请求
			response = httpClient.execute(httpPost);
			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(Optional.ofNullable(response).isPresent()){
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
 
		return resultString;
	}
    
    public static String doPostJson(String url, String body) {
		// 创建Httpclient对象
		CloseableHttpResponse response = null;
		String resultString = "";
		try {
			// 创建Http Post请求
			HttpPost httpPost = new HttpPost(url);
			httpPost.setHeader("Content-Type", ContentType.APPLICATION_JSON.name);
			// 创建参数列表
			httpPost.setEntity(new StringEntity(body,"UTF-8"));
			// 执行http请求
			response = httpClient.execute(httpPost);
			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(Optional.ofNullable(response).isPresent()){
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
 
		return resultString;
	}
    
    public static String doPostFrom(String url, Map<String, String> param,Header...headers) {
		// 创建Httpclient对象
		CloseableHttpResponse response = null;
		String resultString = "";
		try {
			// 创建Http Post请求
			HttpPost httpPost = new HttpPost(url);
			httpPost.setHeader("Content-Type", ContentType.APPLICATION_FORM_URLENCODED.name);
			if(headers != null){
                for (int i = 0; i <headers.length; i++) {
                	httpPost.addHeader(headers[i]);
                }
            }
			// 创建参数列表
			if (param != null) {
				List<NameValuePair> paramList = new ArrayList<>();
				for (String key : param.keySet()) {
					paramList.add(new BasicNameValuePair(key, param.get(key)));
				}
				// 模拟表单
				UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"utf-8");
				httpPost.setEntity(entity);
			}
			// 执行http请求
			response = httpClient.execute(httpPost);
			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(Optional.ofNullable(response).isPresent()){
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
 
		return resultString;
	}

    
    /**
     * get 请求
     * @param url
     * @param param
     * @return
     */
    public static String get(String url, Map<String, String> param) {
		// 创建Httpclient对象
		String resultString = "";
		CloseableHttpResponse response = null;
		try {
			// 创建uri
			URIBuilder builder = new URIBuilder(url);
			if (param != null) {
				for (String key : param.keySet()) {
					builder.addParameter(key, param.get(key));
				}
			}
			URI uri = builder.build();
			// 创建http GET请求
			HttpGet httpGet = new HttpGet(uri);
			// 执行请求
			response = httpClient.execute(httpGet);
			// 判断返回状态是否为200
			if (response.getStatusLine().getStatusCode() == 200) {
				resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if(Optional.ofNullable(response).isPresent()){
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return resultString;
	}


    /**
     * 将url和map数据封装成url携带的参数
     * @param map 要传输的数据
     * @return 携带参数的url
     */
    private static String mapToUrlString(String url,Map<String,Object> map){
        StringBuffer sb = null;
        if(map != null && map.size()>0){
            sb = new StringBuffer();
            Set<String> set = map.keySet();
            for (String s:set) {
                sb.append(s+"="+map.get(s));
                sb.append("&");
            }
        }
        if(sb != null){
            String pramas = sb.toString().substring(0,sb.length()-1);
            //地址自身没有带参数
            if(url.lastIndexOf("?") == -1){
                url = url + "?" + pramas;
            }else{//地址自身带有参数
                url = url + "&" + pramas;
            }
        }
        return url;
    }


}
